package atguigu.shijianduanquchongbingleijia;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class TimerHelper {

    /**
     * 时间区间去重和合并
     * 
     * @param timeBucketList 时间区间
     * @return
     * @throws ParseException
     * 
     *                        Remove the repeated time period
     */
    public List<TimeBucket> rmReptTimePeriod(List<TimeBucket> timeBucketList) throws ParseException {

        List<TimeBucket> res = new ArrayList<>();

        if (timeBucketList.size() < 1)
            return res;

        Map<Date, Date> m = new HashMap<>(); // 存放最后的时间区间结果

        TimeBucket firstTimeBucket = timeBucketList.get(0);
        m.put(firstTimeBucket.getStart(), firstTimeBucket.getEnd());

        for (int i = 1; i < timeBucketList.size(); i++) {
            setAfterCompare(m, timeBucketList.get(i));
        }

        for (Map.Entry<Date, Date> entry : m.entrySet()) {
            if (entry.getKey() == null)
                continue;
            if (entry.getValue() == null)
                continue;

            TimeBucket tb = new TimeBucket(entry.getKey(), entry.getValue());
            res.add(tb);
        }
        return res;
    }

    public int checkTimeBucket(TimeBucket a, TimeBucket b) {
        int v = 0;
        // a 和b 不相交，也不包含 v= 0
        if (a.getEnd().before(b.getStart()) || a.getStart().after(b.getEnd())) {
            v = 0;
        }
        // a 包含b v = 1
        if (a.getStart().before(b.getStart()) && a.getEnd().after(b.getEnd())) {
            v = 1;
        }
        // a 左交b v = 2
        if (a.getStart().before(b.getStart()) && a.getEnd().after(b.getStart())) {
            v = 2;
        }
        // a 右交b v = 3
        if (a.getStart().after(b.getStart()) && a.getStart().before(b.getEnd())) {
            v = 3;
        }
        // b 包含 a v = 4
        if (a.getStart().after(b.getStart()) && a.getEnd().before(b.getEnd())) {
            v = 4;
        }
        // a 和 b 相等
        if (a.getStart().equals(b.getStart()) && a.getEnd().equals(b.getEnd())) {
            v = 5;
        }
        return v;
    }

    public void setAfterCompare(Map<Date, Date> m, TimeBucket b) {
        int len = 0;
        Set<Date> removeItems = new HashSet<>();

        TimeBucket timeBucket = null;

        for (Map.Entry<Date, Date> entry : m.entrySet()) {
            if (entry.getKey() == null)
                continue;
            if (entry.getValue() == null)
                continue;
            TimeBucket a = new TimeBucket(entry.getKey(), entry.getValue()); // map 中的

            Date tempStart = null;
            Date tempEnd = null;

            int v = checkTimeBucket(a, b);
            if (v == 0) { // a 和 b 不相交
                len += 1;
                continue;
            } else if (v == 1) { // a 包含 b
            } else if (v == 2) { // a 左交 b
                tempStart = a.getStart();
                tempEnd = b.getEnd();
                timeBucket = new TimeBucket(tempStart, tempEnd);
                removeItems.add(a.getStart()); // 移除旧数据
                break;
            } else if (v == 3) { // a 右交 b
                tempStart = b.getStart();
                tempEnd = a.getEnd();
                timeBucket = new TimeBucket(tempStart, tempEnd);
                removeItems.add(a.getStart()); // 移除旧数据
                break;
            } else if (v == 4) { // b 包含 a
                tempStart = b.getStart();
                tempEnd = b.getEnd();
                timeBucket = new TimeBucket(tempStart, tempEnd);
                removeItems.add(a.getStart()); // 移除旧数据
                break;
            } else if (v == 5) { // a 和 b 相等
                continue;
            }
        }

        // 和 map 中所有的记录都没有交集
        if (len == m.keySet().size()) {
            if (b.getStart() != null && b.getEnd() != null) {
                m.put(b.getStart(), b.getEnd());
            }
        } else {
            if (removeItems.size() > 0) {
                // 对map进行处理
                for (Date key : removeItems) {
                    m.remove(key);
                }
                removeItems.clear();
            }
            // 增加新添加的
            if (timeBucket != null) {
                setAfterCompare(m, timeBucket);
            }
        }
    }

    /**
     * 累加时间段，算出总的小时数
     * 
     * @param list 时间段列表
     * @return
     */
    public Long sumTimeBucketList(List<TimeBucket> list) {
        long uh = 0;
        long um = 0;
        long us = 0;
        for (TimeBucket timeBucket : list) {

            System.out.println(formatDate2YMDHMS(timeBucket.getStart()));
            System.out.println(formatDate2YMDHMS(timeBucket.getEnd()));

            uh += getHourBetween(timeBucket.getStart(), timeBucket.getEnd());
            um += getMinBetween(timeBucket.getStart(), timeBucket.getEnd());
            us += getSecondBetween(timeBucket.getStart(), timeBucket.getEnd());

            System.out.println(getHourBetween(timeBucket.getStart(), timeBucket.getEnd()) + " 小时");
            System.out.println(getMinBetween(timeBucket.getStart(), timeBucket.getEnd()) + " 分钟");
            System.out.println(getSecondBetween(timeBucket.getStart(), timeBucket.getEnd()) + " 秒");
            System.out.println("============================================");
        }

        return ((um / 60) > uh ? (um / 60) : uh) > (us / 60 / 60) ? ((um / 60) > uh ? (um / 60) : uh) : (us / 60 / 60);
    }

    public String formatDate2YMDHMS(Date d) {
        SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (d == null)
            return "";
        return date.format(d);
    }

    public long getHourBetween(Date begin, Date end) {
        if (begin != null && end != null) {
            LocalDateTime localDateTime1 = date2localDateTime(begin);
            LocalDateTime localDateTime2 = date2localDateTime(end);
            Duration between = Duration.between(localDateTime1, localDateTime2);
            long l = between.toHours();
            // 针对那种因为1秒钟漏了一小时的情况
            long l1 = between.getSeconds() % 3600; // 多出来的秒
            if (l1 >= 3599) {
                l += 1;
            }
            return l;
        } else {
            return 0L;
        }
    }

    /**
     * 日期时间转本地的日期时间
     * 
     * @param date
     * @return
     */
    public LocalDateTime date2localDateTime(Date date) {
        if (date == null)
            return null;
        Instant instant = date.toInstant();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return localDateTime;
    }

    public long getMinBetween(Date begin, Date end) {
        LocalDateTime localDateTime1 = date2localDateTime(begin);
        LocalDateTime localDateTime2 = date2localDateTime(end);
        Duration between = Duration.between(localDateTime1, localDateTime2);
        return between.toMinutes();
    }

    public long getSecondBetween(Date begin, Date end) {
        if (begin != null && end != null) {
            LocalDateTime localDateTime1 = date2localDateTime(begin);
            LocalDateTime localDateTime2 = date2localDateTime(end);
            Duration between = Duration.between(localDateTime1, localDateTime2);
            long l = between.getSeconds();
            // 针对那种因为1秒钟漏了一小时的情况
            long l1 = between.getSeconds() % 3600; // 多出来的秒
            if (l1 >= 3599) {
                l += 1;
            }
            return l;
        } else {
            return 0L;
        }
    }

    public Date beginOfDay(Date date) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String format = sdf.format(date);
        format += " 00:00:00";
        return sdf.parse(format);
    }

    public Date endOfDay(Date date) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String format = sdf.format(date);
        format += " 23:59:59";
        return sdf.parse(format);
    }

    public Date localDate2Date(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        java.util.Date date = Date.from(instant);
        return date;
    }

    public Date ofDay(int year, int month, int day) {
        LocalDate of = LocalDate.of(year, month, day);
        Date localDate2Date = localDate2Date(of);
        return localDate2Date;
    }
}
